using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Book.Blog.Core.DTOs;
using Book.Blog.Core.Entities;
using Book.Blog.Core.Entities.Statistics;
using Book.Blog.Core.Interfaces;
using Book.Blog.Infrastructure.Data;

namespace Book.Blog.Infrastructure.Services
{
    public class StatisticsService : IStatisticsService
    {
        private readonly BlogDbContext _context;

        public StatisticsService(BlogDbContext context)
        {
            _context = context;
        }

        public async Task<StatisticsOverviewDTO> GetOverviewAsync(StatisticsRequestDTO request)
        {
            var startDate = request.StartDate ?? DateTime.UtcNow.AddDays(-30);
            var endDate = request.EndDate ?? DateTime.UtcNow;

            var dailyStats = await _context.DailyStatistics
                .Where(s => s.Date >= startDate && s.Date <= endDate)
                .ToListAsync();

            var topPosts = await GetTopPostsAsync(startDate, endDate, 5);
            var topCategories = await GetTopCategoriesAsync(startDate, endDate, 5);
            var topTags = await GetTopTagsAsync(startDate, endDate, 5);

            return new StatisticsOverviewDTO
            {
                TotalPageViews = dailyStats.Sum(s => s.PageViews),
                TotalUsers = await _context.Users.CountAsync(),
                TotalPosts = await _context.Posts.CountAsync(),
                TotalComments = await _context.Comments.CountAsync(),
                TopPosts = topPosts,
                TopCategories = topCategories,
                TopTags = topTags
            };
        }

        public async Task<IEnumerable<PostStatDTO>> GetTopPostsAsync(DateTime? startDate, DateTime? endDate, int top)
        {
            var query = _context.Posts
                .Include(p => p.Author)
                .Where(p => !p.IsDeleted);

            if (startDate.HasValue)
                query = query.Where(p => p.CreatedAt >= startDate.Value);
            if (endDate.HasValue)
                query = query.Where(p => p.CreatedAt <= endDate.Value);

            return await query
                .OrderByDescending(p => p.ViewCount)
                .Take(top)
                .Select(p => new PostStatDTO
                {
                    Id = p.Id,
                    Title = p.Title,
                    ViewCount = p.ViewCount,
                    CommentCount = p.CommentCount,
                    LikeCount = p.LikeCount,
                    CreatedAt = p.CreatedAt
                })
                .ToListAsync();
        }

        public async Task<IEnumerable<CategoryStatDTO>> GetTopCategoriesAsync(DateTime? startDate, DateTime? endDate, int top)
        {
            var query = _context.Categories
                .Include(c => c.Posts)
                .Where(c => !c.IsDeleted);

            return await query
                .OrderByDescending(c => c.Posts.Count)
                .Take(top)
                .Select(c => new CategoryStatDTO
                {
                    Id = c.Id,
                    Name = c.Name,
                    PostCount = c.Posts.Count,
                    ViewCount = c.Posts.Sum(p => p.ViewCount)
                })
                .ToListAsync();
        }

        public async Task<IEnumerable<TagStatDTO>> GetTopTagsAsync(DateTime? startDate, DateTime? endDate, int top)
        {
            var query = _context.Tags
                .Include(t => t.Posts)
                .Where(t => !t.IsDeleted);

            return await query
                .OrderByDescending(t => t.Posts.Count)
                .Take(top)
                .Select(t => new TagStatDTO
                {
                    Id = t.Id,
                    Name = t.Name,
                    PostCount = t.Posts.Count
                })
                .ToListAsync();
        }

        public async Task<IEnumerable<DailyStatisticsDTO>> GetDailyStatisticsAsync(DateTime? startDate, DateTime? endDate)
        {
            var query = _context.DailyStatistics.AsQueryable();

            if (startDate.HasValue)
                query = query.Where(s => s.Date >= startDate.Value);
            if (endDate.HasValue)
                query = query.Where(s => s.Date <= endDate.Value);

            return await query
                .OrderBy(s => s.Date)
                .Select(s => new DailyStatisticsDTO
                {
                    Date = s.Date,
                    PageViews = s.PageViews,
                    UniqueVisitors = s.UniqueVisitors,
                    NewUsers = s.NewUsers,
                    NewPosts = s.NewPosts,
                    NewComments = s.NewComments
                })
                .ToListAsync();
        }

        public async Task<bool> RecordPageViewAsync(PageViewDTO pageView)
        {
            var entity = new PageView
            {
                Path = pageView.Path,
                UserId = pageView.UserId,
                IpAddress = pageView.IpAddress,
                UserAgent = pageView.UserAgent,
                SessionId = pageView.SessionId,
                Referrer = pageView.Referrer
            };

            await _context.PageViews.AddAsync(entity);
            await _context.SaveChangesAsync();
            return true;
        }

        public async Task<bool> RecordUserActionAsync(UserActionDTO userAction)
        {
            var entity = new UserAction
            {
                ActionType = userAction.ActionType,
                EntityType = userAction.EntityType,
                EntityId = userAction.EntityId,
                UserId = userAction.UserId,
                IpAddress = userAction.IpAddress,
                SessionId = userAction.SessionId,
                AdditionalData = userAction.AdditionalData
            };

            await _context.Set<UserAction>().AddAsync(entity);
            await _context.SaveChangesAsync();
            return true;
        }

        public async Task<bool> GenerateDailyStatisticsAsync(DateTime date)
        {
            var startDate = date.Date;
            var endDate = startDate.AddDays(1);

            var stats = new DailyStatistics
            {
                Date = startDate,
                PageViews = await _context.PageViews.CountAsync(p => p.CreatedAt >= startDate && p.CreatedAt < endDate),
                UniqueVisitors = await _context.PageViews
                    .Where(p => p.CreatedAt >= startDate && p.CreatedAt < endDate)
                    .Select(p => p.IpAddress)
                    .Distinct()
                    .CountAsync(),
                NewUsers = await _context.Users.CountAsync(u => u.CreatedAt >= startDate && u.CreatedAt < endDate),
                NewPosts = await _context.Posts.CountAsync(p => p.CreatedAt >= startDate && p.CreatedAt < endDate),
                NewComments = await _context.Comments.CountAsync(c => c.CreatedAt >= startDate && c.CreatedAt < endDate)
            };

            await _context.DailyStatistics.AddAsync(stats);
            await _context.SaveChangesAsync();
            return true;
        }

        public async Task CleanupOldDataAsync(DateTime before)
        {
            var oldPageViews = await _context.PageViews
                .Where(p => p.CreatedAt < before)
                .ToListAsync();

            var oldUserActions = await _context.Set<UserAction>()
                .Where(a => a.CreatedAt < before)
                .ToListAsync();

            _context.PageViews.RemoveRange(oldPageViews);
            _context.Set<UserAction>().RemoveRange(oldUserActions);

            await _context.SaveChangesAsync();
        }
    }
} 